package sg.edu.nus.iss.billing.controller;

import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.*;

import sg.edu.nus.iss.billing.BillingConstants;
import sg.edu.nus.iss.billing.dao.BaseDAO;
import sg.edu.nus.iss.billing.dao.DaoFactory;
import sg.edu.nus.iss.billing.exceptions.ControllerException;
import sg.edu.nus.iss.billing.model.account.Account;
import sg.edu.nus.iss.billing.model.complaint.Complaint;

/**
 * @author EngKhoon, BeeHong, Ananda
 */
public class ComplaintController {
	
	private static int complaint_Counter;
	private Properties properties;
	
	public ComplaintController() {
		super();
		try {
			properties = new Properties();
			FileInputStream in = new FileInputStream(BillingConstants.PROPERTIES_COMPLAINT);
			properties.load(in);
			in.close();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public String addComplaint(Account account, String description, String status, String agent, String remarks) throws ControllerException {
		String complaintId;
		
		//Validate the input data first.
		//If there's any error, just throw an exception, to be caught and displayed at the GUI level
		String errorMsg = validateInput(description);		
		if(!errorMsg.isEmpty()){
			String displayMsg = properties.getProperty("error.message.addUnsuccessful.main");
			displayMsg += errorMsg.toString();
			throw new ControllerException(displayMsg);
		}
		
		try {
			BaseDAO<Account> accountDao = DaoFactory.getAccountDAO(BillingConstants.DATASOURCE_ACCOUNT);
			Complaint complaint = new Complaint(generateComplaintId(), account.getAccountNo(), description, status, agent, remarks, generateDateTime(), " ");
			complaintId = complaint.getComplaintId();
			
			account.getComplaints().add(complaint);
			accountDao.saveElementByPK(account, "accountNo", account.getAccountNo());
		}
		catch(Exception e) {
			e.printStackTrace();
			throw new ControllerException("Unable to add customer due to technical error. \nPlease contact your local administrator.");
		}
		
		return complaintId;
	}
	
	public void updateComplaint(Complaint complaint) throws ControllerException {
		//Validate the input data first.
		//If there's any error, just throw an exception, to be caught and displayed at the GUI level
		String errorMsg = validateInput(complaint.getComplaintDescription());		
		if(!errorMsg.isEmpty()){
			String displayMsg = properties.getProperty("error.message.updateUnsuccessful.main");
			displayMsg += errorMsg.toString();
			throw new ControllerException(displayMsg);
		}
		
		try {
			BaseDAO<Account> accountDao = DaoFactory.getAccountDAO(BillingConstants.DATASOURCE_ACCOUNT);
			
			List<Account> accounts = accountDao.getElementListByAttribute("accountNo", complaint.getAccountNo());
			if(accounts != null && accounts.size() > 0) {
				Account account = accounts.get(0); // Only expecting 1 account to be return.
			
				if(account != null) {
					List<Complaint> complaints = account.getComplaints();
					List<Complaint> updatedComplaints = new ArrayList<Complaint>();
					for(int n = 0; n < complaints.size(); n++) {
						Complaint existingComplaint = complaints.get(n);
						
						if(complaint.getComplaintId().equals(existingComplaint.getComplaintId()))
							updatedComplaints.add(complaint);
						else
							updatedComplaints.add(existingComplaint);
					}
					account.setComplaints(updatedComplaints);
				}
				accountDao.saveElementByPK(account, "accountNo", account.getAccountNo());
			}
		}
		catch(Exception e) {
			e.printStackTrace();
			throw new ControllerException("Unable to update complaint due to technical error. \nPlease contact your local administrator.");
		}
	}
	
	public HashMap<String, List<Complaint>> searchExistingComplaint(String accountNo,String complaintid, String status) throws ControllerException {
		HashMap<String, List<Complaint>> resultMap = new HashMap<String, List<Complaint>>();
		
		try {
			BaseDAO<Account> accountDao = DaoFactory.getAccountDAO(BillingConstants.DATASOURCE_ACCOUNT);
			List<Complaint> matchedComplaints = new ArrayList<Complaint>();
			List<Complaint> complaints = new ArrayList<Complaint>();
			
			List<Account> accounts = accountDao.getElementList();
			for(int n = 0; n < accounts.size(); n++) {
				Account account = accounts.get(n);
				if(account.getComplaints() != null && account.getComplaints().size() > 0)
					complaints.addAll(account.getComplaints());
			}
			
			if(complaints != null && complaints.size() > 0) {
				Iterator<Complaint> compIter = complaints.iterator();
				while(compIter.hasNext()) {
					boolean matchedComplaintId = true;
					boolean matchedAccountNo = true;
					boolean matchedStatus = true;
					Complaint complaint = compIter.next();
					
					if(accountNo != null) {
						int index = complaint.getAccountNo().toUpperCase().indexOf(accountNo.toUpperCase());
						if(index == -1)
							matchedAccountNo = false;
					}
					if(complaintid != null) {
						int index = complaint.getComplaintId().toUpperCase().indexOf(complaintid.toUpperCase());
						if(index == -1)
							matchedComplaintId = false;
					}
					if(status != null) {
						if(!complaint.getComplaintStatus().toString().equals(status))
							matchedStatus = false;
					}
					
					if(matchedAccountNo && matchedComplaintId  && matchedStatus)
						matchedComplaints.add(complaint);
				}
			}
			resultMap.put("complaints", matchedComplaints);
		}
		catch(Exception e) {
			e.printStackTrace();
			throw new ControllerException("Unable to search customer due to technical error. \nPlease contact your local administrator.");
		}
		return resultMap;
	}
	
	//Generate current log Date and Time
	public String generateDateTime() {
		Calendar cal = Calendar.getInstance();
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-hh:mm");
	    
	    return sdf.format(cal.getTime());
    }
	
	//Generate running Complaint ID counter
	private String generateComplaintId()throws Exception {
		String compNoPrefix = "CP-";
		String compNo = null;
		String compNoTs;
		
		Calendar cal = Calendar.getInstance();
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmm-");
	    compNoTs = sdf.format(cal.getTime());
		compNo = compNoPrefix + compNoTs + ++complaint_Counter;
		
		return (compNo);
	}
	
	private String validateInput(String description) {
		StringBuffer errorMsg = new StringBuffer();
		
		if(description == null || "".equals(description))
			errorMsg.append(properties.getProperty("error.message.descriptionMandatory"));
		
		return errorMsg.toString();
	}
}
	